/*
 *文件作用: 测试驱动
 */

#include "leptjson.h"
#include <stdio.h>
#include <stdlib.h>  // strtod():string to double

static int test_count = 0;  //总测试次数
static int test_pass = 0;   //测试通过次数
static int main_ret = 0;    //测试程序返回值，0 for success

//================================Start:  宏====================================
//基本比较宏定义，用以比较预期结果和实际结果是否一致
//参数:
//  - equality: 预期值和实际值判断相等的方式
//  - expect: 预期值
//  - actual: 实际值
//  - format: 发生错误时, expect 和 actual 的输出格式
#define EXPECT_EQ_BASE(equality, expect, actual, format)                       \
    do {                                                                       \
        test_count++;                                                          \
        if (equality) {                                                        \
            test_pass++;                                                       \
        } else {                                                               \
            fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n",  \
                    __FILE__, __LINE__, expect, actual);                       \
            main_ret = 1;                                                      \
        }                                                                      \
    } while (0)

//比较预期结果和实际结果，指定以int作为格式化方式，基于基本比较宏。结果不匹配时打印错误位置和数值信息。
//参数:
//  - expect: 预期结果
//  - actual: 实际结果
#define EXPECT_EQ_INT(expect, actual)                                          \
    EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")

//同 EXPECT_EQ_INT, 但以 double 打印 expect 和 actual。
#define EXPECT_EQ_DOUBLE(expect, actual)                                       \
    EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%e")

//错误码测试宏，要求出现错误时能给出预期错误码，并将节点类型强制置为 LETP_NULL
//参数:
//  - error: 预期错误码
//  - json: json字符串
#define TEST_ERROR(error, json)                                                \
    do {                                                                       \
        lept_value v;                                                          \
        v.type = LEPT_FALSE;                                                   \
        EXPECT_EQ_INT(error, lept_parse(&v, json));                            \
        EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));                           \
    } while (0)

//针对 true, false, null 的value解析测试宏，以 LEPT_NULL
//初始化节点类型，要求解析成功，并正确修改节点类型 参数:
//  - expect_type: 预期结果类型
//  - json: json字符串
#define TEST_LITERAL(expect_type, json)                                        \
    do {                                                                       \
        lept_value v;                                                          \
        v.type = LEPT_NULL;                                                    \
        EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json));                    \
        EXPECT_EQ_INT(expect_type, lept_get_type(&v));                         \
    } while (0)

// number 测试宏，检查解析是否成功,以及解析结果类型和解析结果数值
//参数:
//  - expect: 预期结果数字的值
//  - json: json字符串
#define TEST_NUMBER(expect, json)                                              \
    do {                                                                       \
        lept_value v;                                                          \
        EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json));                    \
        EXPECT_EQ_INT(LEPT_NUMBER, lept_get_type(&v));                         \
        EXPECT_EQ_DOUBLE(expect, lept_get_number(&v));                         \
    } while (0)
//================================End:  宏====================================

//=============================Start: 字面量====================================
// true, false, null 字面量解析测试集合
static void test_parse_expect_literal() {
    TEST_LITERAL(LEPT_TRUE, "true");    //测试true值解析
    TEST_LITERAL(LEPT_FALSE, "false");  //测试false值解析
    TEST_LITERAL(LEPT_NULL, "null");    //测试null值解析
}

//非法字面量解析测试集合
static void test_parse_invalid_literal() {
    TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "false f");  //测试多值输入
    TEST_ERROR(LEPT_PARSE_EXPECT_VALUE, " \t\n\r");       //测试无值输入
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "monday");       //测试非法输入
}

//字面量解析集合
static void test_parse_literal() {
    test_parse_expect_literal();   //测试合法字面量
    test_parse_invalid_literal();  //测试非法字面量
}
//===========================End: 字面量===============================

//===========================Start:  数字==============================
// number 解析测试集合
static void test_parse_expect_number() {
    TEST_NUMBER(0.0, "0");
    TEST_NUMBER(0.0, "-0");
    TEST_NUMBER(0.0, "-0.0");
    TEST_NUMBER(1.0, "1");
    TEST_NUMBER(-1.0, "-1");
    TEST_NUMBER(1.5, "1.5");
    TEST_NUMBER(-1.5, "-1.5");
    TEST_NUMBER(3.1416, "3.1416");
    TEST_NUMBER(1E10, "1E10");
    TEST_NUMBER(1e10, "1e10");
    TEST_NUMBER(1E+10, "1E+10");
    TEST_NUMBER(1E-10, "1E-10");
    TEST_NUMBER(-1E10, "-1E10");
    TEST_NUMBER(-1e10, "-1e10");
    TEST_NUMBER(-1E+10, "-1E+10");
    TEST_NUMBER(-1E-10, "-1E-10");
    TEST_NUMBER(1.234E+10, "1.234E+10");
    TEST_NUMBER(1.234E-10, "1.234E-10");
    TEST_NUMBER(0.0, "1e-10000"); /* must underflow */

    TEST_NUMBER(1.0000000000000002,
                "1.0000000000000002");  // the smallest number > 1
    TEST_NUMBER(4.9406564584124654e-324,
                "4.9406564584124654e-324");  // Min. subnormal positive double
    TEST_NUMBER(-4.9406564584124654e-324, "-4.9406564584124654e-324");
    TEST_NUMBER(2.2250738585072009e-308,
                "2.2250738585072009e-308");  // Max. subnormal double
    TEST_NUMBER(-2.2250738585072009e-308, "-2.2250738585072009e-308");  //
    TEST_NUMBER(2.2250738585072014e-308,
                "2.2250738585072014e-308");  // Min. normal positive double
    TEST_NUMBER(-2.2250738585072014e-308, "-2.2250738585072014e-308");
    TEST_NUMBER(1.7976931348623157e308,
                "1.7976931348623157e308");  // Max. Double
    TEST_NUMBER(-1.7976931348623157e308, "-1.7976931348623157e308");
}

//测试非法数字
static void test_parse_invalid_number() {
    /* invalid number */
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+0");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+1");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE,
               ".123");  // at least one digit before '.'
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "1.");  // at least one digit after '.'
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "INF");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "inf");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "NAN");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "nan");
}

static void test_parse_number() {
    test_parse_expect_number();   //测试合法数字
    test_parse_invalid_number();  //测试非法数字
}
//===========================End:  数字==============================

//解析测试
static void test_parse() {
#if 0
#    if 0
    test_parse_expect_literal();   //解析value字面量: true, false, null
    test_parse_invalid_literal();  //解析非法字面量
#    endif
    test_parse_expect_number();
    test_parse_invalid_number();
#endif
}

int main(void) {
    test_parse();  //测试解析

    //打印通过次数、总测试次数、通过率
    printf("%d / %d (%3.2f%%) passed\n", test_pass, test_count,
           test_pass * 100.0 / test_count);
    return main_ret;
}